from flask import g
from mongoengine import connect
import pigpio
import json
import time
import config
import hashlib
import base64
from copy import deepcopy


class HttpException(Exception):
    def __init__(self, message, status=500):
        super().__init__(message, status)
        self.message = message
        self.status = status

    def response(self):
        return {'message': self.message, 'status': self.status}


def mongo_connect(db='raspi'):
    connect(db, host='127.0.0.1', port=27017)


def gpio_connect():
    g.pi = pigpio.pi('localhost', 8888)


def gpio_close():
    g.pi.stop()


def bytes2human(n):
    # http://code.activestate.com/recipes/578019
    # >>> bytes2human(10000)
    # '9.8K'
    # >>> bytes2human(100001221)
    # '95.4M'
    if not isinstance(n, int):
        return n

    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
    prefix = {}

    for i, s in enumerate(symbols):
        prefix[s] = 1 << (i + 1) * 10

    for s in reversed(symbols):
        if n >= prefix[s]:
            value = float(n) / prefix[s]
            return '%.1f%s' % (value, s)

    return "%sB" % n


def list_chunk(list_data, n):
    for i in range(0, len(list_data), n):
        yield list_data[i:i + n]


def list_join(list_data):
    str_ = ''
    for item in list_data:
        str_ += str(item)
    return str_


def dict_hash(_dict):
    string = json.dumps(sorted(_dict.items()))

    sha1 = hashlib.md5()
    sha1.update(string.encode('utf-8'))
    return sha1.hexdigest()


def generate_token(data=None):
    data_hash = dict_hash(data)
    identity = str(config.device_name)
    timestamp = str(time.time())
    key = str(config.secret_key)

    sha1 = hashlib.sha1()
    sha1.update((data_hash+identity+timestamp+key).encode('utf-8'))
    token = sha1.hexdigest()

    return base64.b64encode(json.dumps({'identity': identity, 'timestamp': timestamp, 'token': token}).encode('utf-8'))


def validate_token(data, header_token, time_limit=config.http_time):
    data_hash = dict_hash(data)
    print(data_hash)
    key = str(config.secret_key)
    now = time.time()

    try:
        header_token = json.loads(base64.b64decode(header_token).decode('utf-8'))
        sha1 = hashlib.sha1()
        sha1.update((data_hash+header_token['identity']+header_token['timestamp']+key).encode('utf-8'))
        token = sha1.hexdigest()

        return token == header_token['token'] and (now - float(header_token['timestamp']) < time_limit)
    except Exception:
        return False


def data_serial(data, serials):
    result = []
    for row in data:
        for serial in serials:
            new_row = deepcopy(row)
            new_row['serial'] = serial
            new_row['serial_val'] = row.get(serial, None)
            result.append(new_row)

    return result


def data_map(data, maps):
    result = []
    for row in data:
        for mapper in maps:
            # 只增加新元素不删除原有元素
            row[mapper[1]] = row.get(mapper[0], None)
        result.append(row)

    return result
